import { theme as antdTheme } from 'antd';

import { DARK_CLASS } from '@/constants/app';
import { getColorPalette, getRgb, transformColorWithOpacity } from '@/layout/modules/color';
import { overrideThemeSettings, themeSettings } from '@/theme/settings';
import { themeVars } from '@/theme/vars';
import { toggleHtmlClass } from '@/utils/common';
import { localStg } from '@/utils/storage';

import type { ConfigProviderProps } from 'antd';

/**
 * 主题相关工具函数集合
 * 提供主题初始化、变量管理、样式生成等功能
 */

/**
 * 初始化主题设置
 * @returns {App.Theme.ThemeSetting} 返回主题设置对象
 *
 * @description
 * 1. 开发模式下直接返回默认主题设置
 * 2. 生产模式下从localStorage读取主题设置
 * 3. 如果未覆盖过主题设置，则应用覆盖设置并标记
 */
export function initThemeSettings() {
	// 判断是否为生产环境
	const isProd = import.meta.env.PROD;

	// 开发模式直接返回默认设置
	if (!isProd) return themeSettings;

	// 生产模式从localStorage读取设置
	const settings = localStg.get('themeSettings', themeSettings);

	// 检查是否已覆盖主题设置
	const isOverride = localStg.get('overrideThemeFlag') === BUILD_TIME;

	// 未覆盖则应用覆盖设置
	if (!isOverride) {
		Object.assign(settings, overrideThemeSettings);
		localStg.set('overrideThemeFlag', BUILD_TIME);
	}

	return settings;
}

/**
 * 根据主题令牌生成CSS变量字符串
 * @param {App.Theme.BaseToken} tokens - 主题令牌对象
 * @returns {string} 生成的CSS变量字符串
 *
 * @description
 * 1. 处理颜色值时转换为RGB格式
 * 2. 生成CSS变量声明字符串
 */
function getCssVarByTokens(tokens: App.Theme.BaseToken) {
	const styles: string[] = [];

	// 移除var()包装
	function removeVarPrefix(value: string) {
		return value.replace('var(', '').replace(')', '');
	}

	// 移除rgb()包装
	function removeRgbPrefix(value: string) {
		return value.replace('rgb(', '').replace(')', '');
	}

	// 遍历主题变量
	for (const [key, tokenValues] of Object.entries(themeVars)) {
		for (const [tokenKey, tokenValue] of Object.entries(tokenValues)) {
			let cssVarsKey = removeVarPrefix(tokenValue);
			let cssValue = tokens[key][tokenKey];

			// 特殊处理颜色值
			if (key === 'colors') {
				cssVarsKey = removeRgbPrefix(cssVarsKey);
				const { b, g, r } = getRgb(cssValue);
				cssValue = `${r} ${g} ${b}`;
			}

			styles.push(`${cssVarsKey}: ${cssValue}`);
		}
	}

	return styles.join(';');
}

/**
 * 将主题变量添加到全局样式
 * @param {App.Theme.BaseToken} tokens - 亮色主题令牌
 * @param {App.Theme.BaseToken} darkTokens - 暗色主题令牌
 *
 * @description
 * 1. 生成亮色和暗色主题的CSS变量
 * 2. 创建或更新style标签
 * 3. 将样式添加到文档头部
 */
export function addThemeVarsToGlobal(tokens: App.Theme.BaseToken, darkTokens: App.Theme.BaseToken) {
	const cssVarStr = getCssVarByTokens(tokens);
	const darkCssVarStr = getCssVarByTokens(darkTokens);

	const css = `
   :root {
      ${cssVarStr}
    }
  `;

	const darkCss = `
    html.${DARK_CLASS} {
      ${darkCssVarStr}
    }
  `;

	const styleId = 'theme-vars';
	const style = document.querySelector(`#${styleId}`) || document.createElement('style');
	style.id = styleId;
	style.textContent = css + darkCss;
	document.head.appendChild(style);
}

/**
 * 创建主题调色板颜色
 * @param {App.Theme.ThemeColor} colors - 主题基础颜色对象
 * @param {boolean} [recommended=false] - 是否使用推荐的颜色调色板
 * @returns {App.Theme.ThemePaletteColor} 主题调色板颜色对象
 *
 * @description
 * 1. 遍历主题基础颜色，为每种颜色生成调色板
 * 2. 设置基础颜色值（500色号）
 * 3. 为每种颜色生成不同色号（50-950）的变体
 * 4. 返回完整的调色板颜色对象
 */
function createThemePaletteColors(colors: App.Theme.ThemeColor, recommended = false) {
	// 获取所有颜色键
	const colorKeys = Object.keys(colors) as App.Theme.ThemeColorKey[];
	// 初始化调色板对象
	const colorPaletteVar = {} as App.Theme.ThemePaletteColor;

	// 遍历每种颜色
	colorKeys.forEach(key => {
		// 获取颜色调色板
		const colorMap = getColorPalette(colors[key], recommended);

		// 设置基础颜色值（500色号）
		colorPaletteVar[key] = colorMap.get(500)!;

		// 生成不同色号的变体
		colorMap.forEach((hex, number) => {
			colorPaletteVar[`${key}-${number}`] = hex;
		});
	});

	return colorPaletteVar;
}

/**
 * 创建主题令牌
 * @param {App.Theme.ThemeColor} colors - 主题基础颜色
 * @param {App.Theme.ThemeSetting['tokens']} [tokens] - 可选的主题令牌配置
 * @param {boolean} [recommended=false] - 是否使用推荐的颜色调色板
 * @returns {Object} 包含亮色和暗色主题令牌的对象
 * @property {App.Theme.ThemeTokenCSSVars} darkThemeTokens - 暗色主题令牌
 * @property {App.Theme.ThemeTokenCSSVars} themeTokens - 亮色主题令牌
 *
 * @description
 * 1. 基于基础颜色创建调色板颜色
 * 2. 合并传入的令牌配置或使用默认配置
 * 3. 构建亮色和暗色主题令牌
 * 4. 返回包含两种主题令牌的对象
 */
function createThemeToken(
	colors: App.Theme.ThemeColor,
	tokens?: App.Theme.ThemeSetting['tokens'],
	recommended = false
) {
	// 创建调色板颜色
	const paletteColors = createThemePaletteColors(colors, recommended);

	// 使用传入的令牌或默认令牌
	const { dark, light } = tokens || themeSettings.tokens;

	// 构建亮色主题令牌
	const themeTokens: App.Theme.ThemeTokenCSSVars = {
		boxShadow: {
			...light.boxShadow // 合并盒阴影配置
		},
		colors: {
			...paletteColors, // 基础调色板颜色
			nprogress: paletteColors.primary, // 进度条颜色使用主色
			...light.colors // 合并亮色配置
		}
	};

	// 构建暗色主题令牌
	const darkThemeTokens: App.Theme.ThemeTokenCSSVars = {
		boxShadow: {
			...themeTokens.boxShadow, // 继承亮色盒阴影
			...dark?.boxShadow // 合并暗色盒阴影覆盖
		},
		colors: {
			...themeTokens.colors, // 继承亮色颜色
			...dark?.colors // 合并暗色颜色覆盖
		}
	};

	return {
		darkThemeTokens,
		themeTokens
	};
}

/**
 * 获取Ant Design主题配置
 * @param {App.Theme.ThemeColor} colors - 主题颜色配置
 * @param {boolean} darkMode - 是否为暗黑模式
 * @param {App.Theme.ThemeSetting['tokens']} tokens - 主题令牌配置
 * @returns {ConfigProviderProps['theme']} Ant Design主题配置对象
 *
 * @description
 * 1. 根据darkMode选择使用暗黑算法或默认算法
 * 2. 设置组件样式覆盖，包括Button、Collapse、Menu等
 * 3. 配置主题令牌，包括颜色、背景等
 */
export function getAntdTheme(
	colors: App.Theme.ThemeColor,
	darkMode: boolean,
	tokens: App.Theme.ThemeSetting['tokens']
) {
	// 获取Ant Design提供的主题算法
	const { darkAlgorithm, defaultAlgorithm } = antdTheme;

	// 解构主题颜色
	const { error, info, primary, success, warning } = colors;

	// 计算菜单项选中背景色，暗黑模式下透明度为0.3，亮色模式下为0.1
	const bgColor = transformColorWithOpacity(
		primary,
		darkMode ? 0.3 : 0.1,
		darkMode ? '#000000' : '#fff'
	);
	// 获取容器背景色，根据模式选择暗黑或亮色配置
	const containerBgColor = darkMode
		? tokens.dark?.colors?.container
		: tokens.light?.colors.container;

	// 构建Ant Design主题配置
	const theme: ConfigProviderProps['theme'] = {
		// 使用算法数组，支持多种算法组合
		algorithm: [darkMode ? darkAlgorithm : defaultAlgorithm],
		// 组件样式覆盖
		components: {
			Button: {
				controlHeightSM: 28 // 小号按钮高度
			},
			Collapse: {
				contentPadding: '16px 16px 24px 16px', // 内容区域内边距
				headerBg: containerBgColor // 头部背景色
			},
			Menu: {
				darkItemBg: 'transparent', // 暗黑模式菜单项背景透明
				darkSubMenuItemBg: 'transparent', // 暗黑模式子菜单背景透明
				itemMarginInline: 8, // 菜单项水平间距
				itemSelectedBg: bgColor, // 选中项背景色
				subMenuItemBg: 'transparent' // 子菜单背景透明
			}
		},
		// 启用CSS变量
		cssVar: true,
		// 主题令牌配置
		token: {
			colorBgContainer: containerBgColor, // 容器背景色
			colorError: error, // 错误色
			colorInfo: info, // 信息色
			colorPrimary: primary, // 主色
			colorSuccess: success, // 成功色
			colorWarning: warning // 警告色
		}
	};

	return theme;
}

/**
 * 切换辅助颜色模式
 * @param {boolean} [colourWeakness=false] - 是否启用色弱模式
 *
 * @description
 * 色弱模式下会应用80%的反转滤镜
 */
export function toggleAuxiliaryColorModes(colourWeakness = false) {
	const htmlElement = document.documentElement;
	htmlElement.style.filter = colourWeakness ? 'invert(80%)' : '';
}

/**
 * 设置主题变量到HTML元素
 * @param {App.Theme.ThemeColor} themeColors - 主题颜色
 * @param {App.Theme.ThemeSetting['tokens']} [tokens] - 可选的主题令牌
 *
 * @description
 * 1. 创建主题令牌
 * 2. 添加主题变量到全局
 * 3. 切换HTML类名
 */
export function setupThemeVarsToHtml(
	themeColors: App.Theme.ThemeColor,
	tokens?: App.Theme.ThemeSetting['tokens'],
	recommended = false
) {
	const { darkThemeTokens, themeTokens } = createThemeToken(themeColors, tokens, recommended);
	addThemeVarsToGlobal(themeTokens, darkThemeTokens);
}

export function toggleGrayscaleMode(grayscaleMode = false) {
	const GRAYSCALE_CLASS = 'grayscale';

	const { add, remove } = toggleHtmlClass(GRAYSCALE_CLASS);

	if (grayscaleMode) {
		add();
	} else {
		remove();
	}
}
